
function nodeText(n) {
  var s = "";
  for (c = n.firstChild;
       c;
       c = c.nextSibling)
  {
    if (c.nodeType != 3)
      break;
    s += c.textContent;
  }

  return s;
}


function parseRenderBuffer (xml, node, fname) 
{
  var components = node.getAttribute('components');
  
  var type = node.getAttribute('type');
  
  if (type == "float")
    type = parseFloat;
  else if (type == "uint")
    type = parseInt;
  else
    return [];
    
  function nsResolver(prefix) {
    var ns = {
      'c' : 'http://crystalspace.org/xml/library'
    };
    return ns[prefix] || null;
  }
  
  var res = Array();
  var iterator = xml.evaluate('c:e', node, nsResolver, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null ); 
   
  var thisNode = iterator.iterateNext();  
  while (thisNode) 
  {  
    var i = [0, 1, 2];
    if (fname == 'position')
      i = [0, 2, 1];
    for (var c = 0; c < components; c++)
    {
      res.push( type(thisNode.getAttribute('c'+i[c])) );
    }
    thisNode = iterator.iterateNext();  
  }  
  return res;
}

function runSoon(f) {
  setTimeout(f, 0);
}

function CSFile() {
}

CSFile.prototype = {
  load: function cs_load (src) {
    var xhr = new XMLHttpRequest();
    var self = this;
    xhr.onreadystatechange = function () {
      if (xhr.readyState == 4 && xhr.status == 200) {
        runSoon(function () {
                  var xml = xhr.responseXML;
 
                  self.parse(xml);

                  if (self._loadHandler) {
                    runSoon(function () { self._loadHandler.apply(window); });
                  }
                });
      }
    };

    xhr.open("GET", src, true);
    xhr.overrideMimeType("text/xml");
    xhr.setRequestHeader("Content-Type", "text/xml");
    xhr.send(null);
  },

  parse: function cs_parse (xml) {
    function nsResolver(prefix) {
      var ns = {
        'c' : 'http://crystalspace.org/xml/library'
      };
      return ns[prefix] || null;
    }


    function getNode(xpathexpr, ctxNode) {
      if (ctxNode == null)
        ctxNode = xml;
      return xml.evaluate(xpathexpr, ctxNode, nsResolver, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
    }


    // pull out the mesh geometry
    var meshNode = getNode('//c:library/c:meshfact/c:params');
    if (!meshNode) {
      alert("Couldn't find mesh node");
      return false;
    }

    this.gn = getNode;
    this.meshNode = meshNode;
    
    var mesh = {};

    // then we have position, normal, texcoord float_arrays to pull out
    var farrays = ['position', 'normal', 'texture coordinate 0'];
    for (var i = 0; i < farrays.length; ++i) {
      var fname = farrays[i];

      var fnode = getNode('//c:renderbuffer[@name="' + fname + '"]', meshNode);
      if (!fnode) {
        alert("Missing " + fname + " float_array in mesh node");
        return false;
      }
      
      if (fname == 'texture coordinate 0')
        fname = 'texcoord';

      mesh[fname] = parseRenderBuffer(xml, fnode, fname);
    }

    // then grab the indices
    var inode = getNode('//c:submesh/c:indexbuffer', meshNode);
    if (!inode) {
      alert("Missing triangles/p in mesh node");
      return false;
    }

    mesh['index'] = parseRenderBuffer(xml, inode);


    // figure out the bounding box
    var minx = Infinity, miny = Infinity, minz = Infinity;
    var maxx = -Infinity, maxy = -Infinity, maxz = -Infinity;
    var npoints = Math.floor(mesh.position.length / 3);
    for (var i = 0; i < npoints; ++i) {
      var x = mesh.position[i*3  ];
      var y = mesh.position[i*3+1];
      var z = mesh.position[i*3+2];

      minx = Math.min(minx, x);
      miny = Math.min(miny, y);
      minz = Math.min(minz, z);

      maxx = Math.max(maxx, x);
      maxy = Math.max(maxy, y);
      maxz = Math.max(maxz, z);
    }

    mesh.bbox = {
      min: { x: minx, y: miny, z: minz },
      max: { x: maxx, y: maxy, z: maxz }
    };


    // now load the textures and kick off the loads
    var textures = { };
    
    var node = getNode('//c:library/c:textures/c:texture/c:file');
    var name = nodeText(node);
    
    
    var img = new Image();
    
    // register a callback for errors, load a standard tex.
    function onerror() 
    {
      img.src = "/webgl/UV_mapper.jpg";
    }
    img.onerror = onerror;
    
    img.src = "/assets/"+name+"/transcode/?format=image/jpeg";
    textures['diffuse'] = img;
    


    this.mesh = mesh;
    this.textures = textures;

    return true;
  },
};
